class Trie:
    class _Node:
        __slots__ = "value", "weight", "children"

        def __init__(self):
            self.value = 0
            self.weight = 0
            self.children = {}

        def __contains__(self, ch):
            return ch in self.children

        def __getitem__(self, ch):
            return self.children[ch]

        def __setitem__(self, ch, value):
            self.children[ch] = value

    def __init__(self):
        self.root = self._Node()

    def insert(self, word: str) -> None:
        node = self.root
        for ch in word:
            if ch not in node:
                node[ch] = self._Node()
            node.weight += 1
            node = node[ch]
        node.weight += 1
        node.value += 1

    def countWordsEqualTo(self, word: str) -> int:
        node = self.root
        for ch in word:
            if ch not in node:
                return 0
            node = node[ch]
        return node.value

    def countWordsStartingWith(self, prefix: str) -> int:
        node = self.root
        for ch in prefix:
            if ch not in node:
                return 0
            node = node[ch]
        return node.weight

    def erase(self, word: str) -> None:
        node = self.root
        for ch in word:
            if ch not in node:
                break
            node.weight -= 1
            node = node[ch]
        node.weight -= 1
        node.value -= 1


if __name__ == "__main__":
    obj = Trie()
    obj.insert("apple")
    obj.insert("apple")
    print(obj.countWordsEqualTo("apple"))  # 2
    print(obj.countWordsStartingWith("app"))  # 2
    obj.erase("apple")
    print(obj.countWordsEqualTo("apple"))  # 1
    print(obj.countWordsStartingWith("app"))  # 1
    obj.erase("apple")
    print(obj.countWordsStartingWith("app"))  # 0
